import os
import getpass

from PySide2.QtWidgets import *
from PySide2.QtCore import Qt, QSize, QRect
from PySide2.QtGui import QFont

from CustStyleSheets import *
from utils import EiiDevHelper


class DeployWgt(QWidget):
    
    def __init__(self, parent=None, root_win=None, 
                 log_console=None, log_proc_flag=None,
                 eii_home="", project_name="", 
                 show_all=True, pwd=""):
        super(DeployWgt, self).__init__(parent=parent)
        self.root_win = root_win
        self.log_console = log_console
        self.log_proc_flag = log_proc_flag
        self.eii_home = eii_home
        self.project_name = project_name
        self.eii_helper_workspace = os.path.join(self.eii_home, 
            "eii_helper/workspace")
        self.show_all = show_all # True: from Test Win; False: from Welcome Win
        # For storing password of the host machine
        self._host_pwd = pwd
        self._eii_easy_helper = None
        
        # List for storing existing projects, which excludes the current project
        # Key: project name
        # Value: checkbox, used to judge whether the project should deploy
        self.existing_projects = {}
        # List for the selected projects
        self.selected_projects = []
        
        self.init_ui()
        self.signals_collector()

    def init_ui(self):
        self.grid_lyt_global = QGridLayout(self)
        self.grid_lyt_global.setContentsMargins(0, 0, 0, 0)
        self.grid_lyt_global.setVerticalSpacing(0)
        self.grid_lyt_global.setHorizontalSpacing(0)

        self.lbl_deployment = QLabel(self)
        self.lbl_deployment.setText("Deployment")
        self.lbl_deployment.setStyleSheet("color: rgb(32, 74, 135);")
        self.lbl_deployment.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
        self.grid_lyt_global.addWidget(self.lbl_deployment, 1, 1, 1, 1)

        self.init_central()

        # Spacers
        spacer_top = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.grid_lyt_global.addItem(spacer_top, 0, 1, 1, 1)
        spacer_bottom = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.grid_lyt_global.addItem(spacer_bottom, 3, 1, 1, 1)
        spacer_left = QSpacerItem(120, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        self.grid_lyt_global.addItem(spacer_left, 1, 0, 1, 1)
        spacer_right = QSpacerItem(120, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        self.grid_lyt_global.addItem(spacer_right, 1, 2, 1, 1)
    
    def init_central(self):
        self.wgt_central = QWidget(self)
        self.wgt_central.setObjectName("wgt_central")
        wgt_central_style = \
        """
        QWidget#wgt_central 
        {
            border: 2px groove gray;
            border-color: rgb(85, 87, 83);
        }
        """
        self.wgt_central.setStyleSheet(wgt_central_style)
        self.grid_lyt_central = QGridLayout(self.wgt_central)
        
        self.init_central_left()
        self.init_central_right()
        # Set default target device to remote
        self.slot_select_target_device(self.radio_btn_remote_device)

        line = QFrame(self.wgt_central)
        line.setFrameShape(QFrame.VLine)
        line.setFrameShadow(QFrame.Sunken)
        self.grid_lyt_central.addWidget(line, 0, 1, 1, 1)

        self.grid_lyt_global.addWidget(self.wgt_central, 2, 1, 1, 1)
    
    def init_central_left(self):
        self.wgt_central_left = QWidget(self.wgt_central)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.wgt_central_left.sizePolicy().hasHeightForWidth())
        self.wgt_central_left.setSizePolicy(sizePolicy)
        self.grid_lyt_central_left = QGridLayout(self.wgt_central_left)

        # Title
        self.lbl_data_streams = QLabel(self.wgt_central_left)
        self.lbl_data_streams.setText("Data Streams")
        self.lbl_data_streams.setMinimumSize(QSize(0, 30))
        self.lbl_data_streams.setMaximumSize(QSize(16777215, 30))
        self.grid_lyt_central_left.addWidget(self.lbl_data_streams, 0, 0, 1, 1)

        self.btn_more = QPushButton(self.wgt_central_left)
        self.btn_more.setText("&Show All")
        self.btn_more.setMinimumSize(QSize(70, 0))
        self.btn_more.setMaximumSize(QSize(70, 16777215))
        self.btn_more.setStyleSheet(SS_MINI_BTN_ENABLE)
        self.grid_lyt_central_left.addWidget(self.btn_more, 0, 1, 1, 1)
        if self.show_all:
            self.btn_more.show()
        else:
            self.btn_more.hide()
        
        # Current data stream
        self.wgt_current_data_stream = QWidget(self.wgt_central_left)
        self.grid_lyt_current_data_stream = QGridLayout(self.wgt_current_data_stream)
        
        self.ckbox_current_data_stream = QCheckBox(self.wgt_current_data_stream)
        self.ckbox_current_data_stream.setText("")
        self.ckbox_current_data_stream.setChecked(True)
        self.grid_lyt_current_data_stream.addWidget(self.ckbox_current_data_stream, 0, 0, 1, 1)
        self.le_current_data_stream = QLineEdit(self.wgt_current_data_stream)
        self.le_current_data_stream.setText(self.project_name)
        self.le_current_data_stream.setReadOnly(True)
        self.grid_lyt_current_data_stream.addWidget(self.le_current_data_stream, 0, 1, 1, 1)
        
        self.grid_lyt_central_left.addWidget(self.wgt_current_data_stream, 1, 0, 1, 2)
        if self.show_all:
            self.wgt_current_data_stream.show()
        else:
            self.wgt_current_data_stream.hide()
        
        # Existing data streams
        self.scroll_area = QScrollArea(self.wgt_central_left)
        if self.show_all:
            self.scroll_area.setStyleSheet("QScrollArea#scrollArea{border: 1px dashed gray;}")
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setObjectName("scrollArea")
        self.scroll_area.setMinimumSize(QSize(0, 200))
        if self.show_all:
            self.scroll_area.hide()
        else:
            self.scroll_area.show()
        self.scroll_area_wgt = QWidget()
        self.grid_lyt_scroll_area = QGridLayout(self.scroll_area_wgt)
        self.scroll_area.setWidget(self.scroll_area_wgt)

        counter_of_existing_projects = 0
        project_list = sorted(os.listdir(self.eii_helper_workspace))
        for project_name in project_list:
            # Exclude the current project name
            if project_name == self.project_name:
                continue
            # Add to window
            ckbox = QCheckBox(self.scroll_area_wgt)
            self.grid_lyt_scroll_area.addWidget(ckbox, counter_of_existing_projects, 0, 1, 1)
            le = QLineEdit(self.scroll_area_wgt)
            le.setText(project_name)
            le.setReadOnly(True)
            self.grid_lyt_scroll_area.addWidget(le, counter_of_existing_projects, 1, 1, 1)
            
            self.existing_projects[project_name] = ckbox
            counter_of_existing_projects += 1
        
        spacer1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.grid_lyt_scroll_area.addItem(spacer1, 99, 1, 1, 1)
        self.grid_lyt_central_left.addWidget(self.scroll_area, 2, 0, 1, 2)
        
        spacer2 = QSpacerItem(40, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.grid_lyt_central_left.addItem(spacer2, 3, 0, 1, 1)
        
        self.grid_lyt_central.addWidget(self.wgt_central_left, 0, 0, 1, 1)

    def init_central_right(self):
        self.wgt_central_right = QWidget(self.wgt_central)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.wgt_central_right.sizePolicy().hasHeightForWidth())
        self.wgt_central_right.setSizePolicy(sizePolicy)
        self.grid_lyt_central_right = QGridLayout(self.wgt_central_right)
        
        # Title
        self.lbl_target_device = QLabel(self.wgt_central_right)
        self.lbl_target_device.setText("Target Device")
        self.lbl_target_device.setMinimumSize(QSize(0, 30))
        self.lbl_target_device.setMaximumSize(QSize(16777215, 30))
        self.grid_lyt_central_right.addWidget(self.lbl_target_device, 0, 0, 1, 2)
        
        # RadioButtons
        self.wgt_target_device = QWidget(self.wgt_central_right)
        self.grid_lyt_target_device = QGridLayout(self.wgt_target_device)
        self.radio_btn_remote_device = QRadioButton(self.wgt_target_device)
        self.radio_btn_remote_device.setText("Remote Device")
        self.radio_btn_remote_device.setChecked(True)
        self.radio_btn_remote_device.toggled.connect(lambda:self.slot_select_target_device(self.radio_btn_remote_device))
        self.grid_lyt_target_device.addWidget(self.radio_btn_remote_device, 0, 0, 1, 1)
        self.radio_btn_local_device = QRadioButton(self.wgt_target_device)
        self.radio_btn_local_device.setText("Local Device")
        self.radio_btn_local_device.toggled.connect(lambda:self.slot_select_target_device(self.radio_btn_local_device))
        self.grid_lyt_target_device.addWidget(self.radio_btn_local_device, 0, 1, 1, 1)
        self.radio_btn_usb_package = QRadioButton(self.wgt_target_device)
        self.radio_btn_usb_package.setText("USB Package")
        self.radio_btn_usb_package.toggled.connect(lambda:self.slot_select_target_device(self.radio_btn_usb_package))
        self.grid_lyt_target_device.addWidget(self.radio_btn_usb_package, 0, 2, 1, 1)
        self.grid_lyt_central_right.addWidget(self.wgt_target_device, 1, 0, 1, 2)
        
        # EditLines
        self.wgt_user_input = QWidget(self.wgt_central_right)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.wgt_user_input.sizePolicy().hasHeightForWidth())
        self.wgt_user_input.setSizePolicy(sizePolicy)
        self.grid_lyt_user_input = QGridLayout(self.wgt_user_input)
        
        self.lbl_device_ip = QLabel(self.wgt_user_input)
        self.lbl_device_ip.setText("Remote IP:")
        self.grid_lyt_user_input.addWidget(self.lbl_device_ip, 0, 0, 1, 1)
        self.le_device_ip = QLineEdit(self.wgt_user_input)
        self.grid_lyt_user_input.addWidget(self.le_device_ip, 0, 1, 1, 1)
        
        self.lbl_username = QLabel(self.wgt_user_input)
        self.lbl_username.setText("Remote Username:")
        self.grid_lyt_user_input.addWidget(self.lbl_username, 1, 0, 1, 1)
        self.le_username = QLineEdit(self.wgt_user_input)
        self.grid_lyt_user_input.addWidget(self.le_username, 1, 1, 1, 1)
        
        self.lbl_password = QLabel(self.wgt_user_input)
        self.lbl_password.setText("Remote Password:")
        self.grid_lyt_user_input.addWidget(self.lbl_password, 2, 0, 1, 1)
        self.le_password = QLineEdit(self.wgt_user_input)
        self.le_password.setEchoMode(QLineEdit.Password)
        self.grid_lyt_user_input.addWidget(self.le_password, 2, 1, 1, 1)

        self.remote_line = QFrame(self.wgt_user_input)
        self.remote_line.setFrameShape(QFrame.HLine)
        self.remote_line.setFrameShadow(QFrame.Sunken)
        self.grid_lyt_user_input.addWidget(self.remote_line, 3, 0, 1, 1)

        self.lbl_host_ip = QLabel(self.wgt_user_input)
        self.lbl_host_ip.setText("Host IP:")
        self.grid_lyt_user_input.addWidget(self.lbl_host_ip, 4, 0, 1, 1)
        self.le_host_ip = QLineEdit(self.wgt_user_input)
        self.grid_lyt_user_input.addWidget(self.le_host_ip, 4, 1, 1, 1)

        self.lbl_sudo_pwd = QLabel(self.wgt_user_input)
        self.lbl_sudo_pwd.setText("Will deploy data streams to local device.\nOnce deployed, check result in web browser.\nLink: localhost:5001")
        self.grid_lyt_user_input.addWidget(self.lbl_sudo_pwd, 5, 0, 1, 1)
        self.btn_stop_local = QPushButton(self.wgt_user_input)
        self.btn_stop_local.setText("Stop Services")
        self.btn_stop_local.setMinimumSize(QSize(100, 16777215))
        self.btn_stop_local.setMaximumSize(QSize(100, 16777215))
        self.btn_stop_local.setStyleSheet(SS_MINI_BTN_ENABLE)
        self.grid_lyt_user_input.addWidget(self.btn_stop_local, 6, 0, 1, 1)

        self.lbl_save_path = QLabel(self.wgt_user_input)
        self.lbl_save_path.setText("Save Path:")
        self.grid_lyt_user_input.addWidget(self.lbl_save_path, 7, 0, 1, 1)
        self.le_save_path = QLineEdit(self.wgt_user_input)
        self.le_save_path.setReadOnly(True)
        self.grid_lyt_user_input.addWidget(self.le_save_path, 7, 1, 1, 1)
        self.btn_save_path = QPushButton(self.wgt_user_input)
        self.btn_save_path.setText("...")
        self.btn_save_path.setMinimumSize(QSize(65, 16777215))
        self.btn_save_path.setMaximumSize(QSize(65, 16777215))
        self.btn_save_path.setStyleSheet(SS_MINI_BTN_ENABLE)
        self.grid_lyt_user_input.addWidget(self.btn_save_path, 7, 2, 1, 1, Qt.AlignHCenter|Qt.AlignVCenter)
        
        spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.grid_lyt_user_input.addItem(spacer, 8, 0, 1, 1)

        self.grid_lyt_central_right.addWidget(self.wgt_user_input, 2, 0, 1, 2)
        
        # PushButtons
        self.wgt_btns = QWidget(self.wgt_central_right)
        self.grid_lyt_btns = QGridLayout(self.wgt_btns)
        
        # self.btn_cancel = QPushButton(self.wgt_btns)
        # self.btn_cancel.setText("&Cancel")
        # self.btn_cancel.setMinimumSize(QSize(70, 0))
        # self.btn_cancel.setMaximumSize(QSize(70, 16777215))
        # self.btn_cancel.setStyleSheet(SS_MINI_BTN_ENABLE)
        # self.grid_lyt_btns.addWidget(self.btn_cancel, 0, 1, 1, 1)
        
        self.btn_deploy = QPushButton(self.wgt_btns)
        self.btn_deploy.setText("&Deploy")
        self.btn_deploy.setMinimumSize(QSize(70, 0))
        self.btn_deploy.setMaximumSize(QSize(70, 16777215))
        self.btn_deploy.setStyleSheet(SS_MINI_BTN_ENABLE)
        self.grid_lyt_btns.addWidget(self.btn_deploy, 0, 2, 1, 1)
        
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.grid_lyt_btns.addItem(spacer, 0, 0, 1, 1)
        
        self.grid_lyt_central_right.addWidget(self.wgt_btns, 3, 0, 1, 2)
        
        self.grid_lyt_central.addWidget(self.wgt_central_right, 0, 2, 1, 1)

    def slot_select_target_device(self, radio_btn):
        if radio_btn.text() == "Remote Device":
            self.lbl_device_ip.show()
            self.le_device_ip.show()
            self.lbl_username.show()
            self.le_username.show()
            self.lbl_password.show()
            self.le_password.show()
            self.remote_line.show()
            self.lbl_host_ip.show()
            self.le_host_ip.show()
            self.lbl_sudo_pwd.hide()
            self.btn_stop_local.show()
            self.lbl_save_path.hide()
            self.le_save_path.hide()
            self.btn_save_path.hide()
        elif radio_btn.text() == "Local Device":
            self.lbl_device_ip.hide()
            self.le_device_ip.hide()
            self.lbl_username.hide()
            self.le_username.hide()
            self.lbl_password.hide()
            self.le_password.hide()
            self.remote_line.hide()
            self.lbl_host_ip.hide()
            self.le_host_ip.hide()
            self.lbl_sudo_pwd.show()
            self.btn_stop_local.show()
            self.lbl_save_path.hide()
            self.le_save_path.hide()
            self.btn_save_path.hide()
        else:
            self.lbl_device_ip.hide()
            self.le_device_ip.hide()
            self.lbl_username.hide()
            self.le_username.hide()
            self.lbl_password.hide()
            self.le_password.hide()
            self.remote_line.hide()
            self.lbl_host_ip.hide()
            self.le_host_ip.hide()
            self.lbl_sudo_pwd.hide()
            self.btn_stop_local.hide()
            self.lbl_save_path.show()
            self.le_save_path.show()
            self.btn_save_path.show()

    def slot_btn_more(self):
        if self.scroll_area.isHidden():
            self.scroll_area.show()
        else:
            self.scroll_area.hide()    

    def slot_btn_save_path(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        options |= QFileDialog.ShowDirsOnly
        selected_dir = str(QFileDialog.getExistingDirectory(
            None, "Select Directory", "/home/{}".format(getpass.getuser()), options=options))
        # Only the selected directory is not an empty string
        if selected_dir != "":
            self.le_save_path.setText(selected_dir)

    def slot_btn_stop_local(self):
        if self._eii_easy_helper is None:
            print("Not deploy yet.")
            return

        if self.radio_btn_remote_device.isChecked():
            remote_device_ip = self.le_device_ip.text()
            remote_device_username = self.le_username.text()
            remote_device_password = self.le_password.text()
            host_ip = self.le_host_ip.text()
            if len(remote_device_ip) == 0 or len(remote_device_username) == 0 or len(remote_device_password) == 0 or len(host_ip) == 0:
                self._show_msg_dialog("InputBox remote ip/remote username/remote password/host ip should not be empty!")
                return
            # Start to stop
            proc = self._eii_easy_helper.stop_remote_services(
                remote_device_ip, remote_device_username, remote_device_password
            )
            self.log_proc_flag.t = proc
            
        elif self.radio_btn_local_device.isChecked():  
            proc = EiiDevHelper.stop_local_services()
            self.log_proc_flag.t = proc

    def slot_btn_deploy(self):
        self.log_console.show()
        self.log_console.clear_text()
        self.root_win.activateWindow()

        # Get selected projects
        self.selected_projects.clear()
        if self.existing_projects.keys():
            for p_name in self.existing_projects.keys():
                ckbox_project = self.existing_projects[p_name]
                if ckbox_project.isChecked():
                    self.selected_projects.append(p_name)
        if self.ckbox_current_data_stream.isChecked() and self.project_name:
            if self.project_name not in self.selected_projects:
                self.selected_projects.append(self.project_name)

        if not self.selected_projects:
            self._show_msg_dialog("No data stream is selected, please select at least one!")
            return

        # Init EII Dev Helper
        self._eii_easy_helper = EiiDevHelper(
            eii_home = self.eii_home,
            project_list = self.selected_projects,
            user_pwd = self._host_pwd,
        )

        # Remote Deploy
        if self.radio_btn_remote_device.isChecked():
            remote_device_ip = self.le_device_ip.text()
            remote_device_username = self.le_username.text()
            remote_device_password = self.le_password.text()
            host_ip = self.le_host_ip.text()
            if len(remote_device_ip) == 0 or len(remote_device_username) == 0 or len(remote_device_password) == 0 or len(host_ip) == 0:
                self._show_msg_dialog("InputBox remote ip/remote username/remote password/host ip should not be empty!")
                return
            # Start to deploy
            proc = self._eii_easy_helper.remote_deploy(
                remote_device_ip, remote_device_username, remote_device_password, host_ip
            )
            self.log_proc_flag.t = proc
        # Local Deploy
        elif self.radio_btn_local_device.isChecked():
            # Start to deploy
            proc = self._eii_easy_helper.local_deploy()
            self.log_proc_flag.t = proc
        # USB Package
        elif self.radio_btn_usb_package.isChecked():
            save_path = self.le_save_path.text()
            if len(save_path) == 0:
                self._show_msg_dialog("InputBox save path should not be empty!")
                return
            # Start to generate
            proc = self._eii_easy_helper.generate_usb_package(save_path)
            self.log_proc_flag.t = proc
        else:
            self._show_msg_dialog("Error deploy radio button!")
            return

    def slot_btn_prev(self):
        self.log_console.hide()
    
    def slot_btn_home(self):
        self.log_console.hide()
    
    def signals_collector(self):
        self.btn_more.clicked.connect(self.slot_btn_more)
        self.btn_deploy.clicked.connect(self.slot_btn_deploy)
        self.btn_stop_local.clicked.connect(self.slot_btn_stop_local)
        self.btn_save_path.clicked.connect(self.slot_btn_save_path)

    def _show_msg_dialog(self, text):
        QMessageBox.warning(self, "Warning", "{}".format(text), QMessageBox.Ok)